﻿<%@ Page Language="C#" AutoEventWireup="true" CodeFile="scoreboard.aspx.cs" Inherits="scoreboard"%>
<%@ import Namespace="RobozzleModel" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Collections.Generic" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">
    <link href="stats.css" rel="stylesheet" type="text/css"/>
    <title>RoboZZle scoreboard</title>
</head>
<body>
<%= StatsCommon.MenuBar(MenuPage.Scoreboard) %>
<h1>RoboZZle Scoreboard</h1>

<p style="text-align:center">
<%
    int activeMode = 0;
    
    string todayParam = Request.Params["today"];
    if (todayParam != null && todayParam == "1") activeMode = 1;

    string shortestParam = Request.Params["shortest"];
    if (shortestParam != null && shortestParam == "1") activeMode = 2;

    string designerParam = Request.Params["designer"];
    if (designerParam != null && designerParam == "1") activeMode = 3;

    string[] modes = new[] { "Most Solved", "Most Solved in Last 24 Hours", "Most Shortest Solutions", "Top Designer" };
    string[] urls = new[] { "", "?today=1", "?shortest=1", "?designer=1" };
    string[] scoreName = new[] { "Solved puzzles", "Solved puzzles", "Shortest solutions", "Designer score" };

    for (int i = 0; i < modes.Length; i++)
    {
        if (i > 0) Response.Write(" | ");
        Response.Write(
            string.Format(
                "{0}{1}{2}",
                activeMode == i ? "<b>" : "<a href=\"scoreboard.aspx" + urls[i] + "\">",
                modes[i],                
                activeMode == i ? "</b>" : "</a>"));
    }
%>
</p>

<table>
<thead>
    <tr>
        <th width="20">Rank</th>
        <th width="100">Player</th>
        <th width="40"><%= scoreName[activeMode] %></th>
    </tr>
</thead>
<%
    RobozzleEntities entities = new RobozzleEntities();

    OddEven oe = new OddEven();
    Action<long?, string, int> writeRow = (rank, userName, solved) =>
    {
        Response.Write(
            string.Format(
                "<tr><td class=\"{3}Row\">{0}</td><td class=\"{3}Row\">{1}</td><td class=\"{3}Row\">{2}</td></tr>",
                rank,
                "<a href='user.aspx?name=" + userName + "'>" + userName + "</a>",
                solved,
                oe.Next()));
    };

    IEnumerable<KeyValuePair<string, int>> scores;
    
    if (activeMode == 0)
    {
        scores = entities.Scoreboard.AsEnumerable().Select(scoreRow => new KeyValuePair<string, int>(scoreRow.UserName, scoreRow.LevelsSolved));
    }
    else if (activeMode == 1)
    {
        scores = entities.TopSolverToday.AsEnumerable()
            .Select(scoreRow => new KeyValuePair<string, int>(scoreRow.UserName, scoreRow.LevelsSolved));
    }
    else if (activeMode == 2)
    {
        var minLengthsForLevel = entities.Solution.Where(s =>s.UserName != null && s.Solution1 != null && s.LevelId >= 0).GroupBy(sol => sol.LevelId).Select(p => new { LevelId = p.Key, MinLength = p.Min(x => x.Solution1.Length) });
        var minLengthsForVisibleLevel =
            minLengthsForLevel.Join(
                entities.LevelVoteCache.Where(r => r.VoteKind == StatsCommon.DIFFICULTY_VOTE),
                r => r.LevelId, r => r.LevelId, (lengths, vote) => new { Lengths = lengths, Vote = vote })
                .Where(r => r.Vote.VoteSum > StatsCommon.BAD_PUZZLE_THRESHOLD)
                .Select(r => r.Lengths);
        var minLengthsForUser = entities.Solution.Where(s => s.UserName != null && s.Solution1 != null && s.LevelId >= 0).GroupBy(sol => new { UserName = sol.UserName, PuzzleId = sol.LevelId }).Select(p => new { UserName = p.Key.UserName, LevelId = p.Key.PuzzleId, MinLength = p.Min(x => x.Solution1.Length) });
        
        var res = minLengthsForUser.Join(
            minLengthsForVisibleLevel, 
            userSolLen => userSolLen.LevelId, 
            levelLen => levelLen.LevelId,
            (userSolLen, levelLen) => new { UserName = userSolLen.UserName, Value = (userSolLen.MinLength == levelLen.MinLength ? 1 : 0) })
        .GroupBy(
            userCnt => userCnt.UserName)
        .Select(userCnts => new { UserName = userCnts.Key, Score = userCnts.Select(c => c.Value).Sum() });

        scores = res.AsEnumerable().Select(scoreRow =>  new KeyValuePair<string, int>(scoreRow.UserName, scoreRow.Score));
    }
    else
    {
        // Top designer
        var q =
            from r in entities.LevelWithDifficulty
            where r.SubmittedBy != null 
            let liked = (r.CoolnessVoteSum + r.CoolnessVoteCount) / 2
            let disliked = (r.CoolnessVoteCount - liked)
            select new { UserName = r.SubmittedBy, Date = r.SubmittedDate, Liked = liked, Disliked = disliked };

        DateTime now = DateTime.Now;
                
        scores = q.AsEnumerable()      
            .GroupBy(r => r.UserName)
            .Select(r => new
            {
                UserName = r.Key,
                Score = r.Sum(x =>
                    100 * Math.Sqrt(Math.Max(0, ((double)x.Liked - 5 * x.Disliked)))
                    * Math.Pow(0.98, (now - x.Date).TotalDays))
            })
            .Where(r => r.Score > 0)
            .Select(scoreRow =>  new KeyValuePair<string, int>(scoreRow.UserName, (int)scoreRow.Score));
    }
    
    int nextRank = 0, curRank = 0;
    int prevScore = int.MaxValue;         
    foreach (var scoreRow in scores.OrderByDescending(r => r.Value).ThenBy(r => r.Key))
    {
        nextRank++;
        if (prevScore > scoreRow.Value) curRank = nextRank;
        prevScore = scoreRow.Value;

        writeRow(curRank, scoreRow.Key, scoreRow.Value);
    }        
%>
</table>

<% if(activeMode == 3) { %>
    <p><small>Designer Score = sum of the Puzzle Scores from the designer</small></p>
    <p><small>Puzzle Score = 100 &#215; sqrt [ max(0, <i>liked</i> - 5 &#215; <i>disliked</i>) ] &#215; 0.98<sup><i>days since posted</i></sup></small></p>
<% } %>

<% Response.Write(StatsCommon.Footer()); %>
</body>
</html>
